package com.george.server;


import com.george.entity.vo.ExceptionVo;
import com.george.enums.ConnectEnum;
import com.george.enums.ExceptionEnum;
import com.george.enums.LinkTypeEnum;
import com.george.enums.OptionEnum;
import com.george.socket.OptionSocket;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Objects;

@Component
@Slf4j
public class TcpServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 需要维护的两个设备
     */
    public static Channel CONNECT_ONE;
    public static Channel CONNECT_TWO;

    /**
     * 注入OptionSocket，用于向移动设备或前端页面实时发送数据
     */
    @Autowired
    private OptionSocket optionSocket;

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        log.debug("设备[{}]加入连接",ctx.channel().id());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        log.debug("收到来自设备[{}]发送的消息:{}",ctx.channel().id() , msg.toString());
        ctx.write("Server has received msg: ["+ msg +"]");
        ctx.flush();
        //如果发送的消息是设备标识符，则进行设备绑定
        ConnectEnum flag = ConnectEnum.getConnectEnumByFlag(msg.toString());
        if (!Objects.isNull(flag)){
            bindDevice(flag,ctx.channel());  //绑定设备
            return;
        }
        //如果发送的消息是控制移动端学习统计时间的指令，则需要将消息对移动端进行转发
        if (Objects.equals(OptionEnum.START.getOrder(),msg.toString()) || Objects.equals(OptionEnum.STOP.getOrder(),msg.toString())){
            try {
                //通过嵌入式设备发来的指令，转换为移动设备能够识别的指令
                String option = OptionEnum.getOptionByOrder(msg.toString());
                optionSocket.sendMessage(LinkTypeEnum.MOBILE,option);
            } catch (IOException e) {
                throw new ExceptionVo(ExceptionEnum.BUSINESS_EXCEPTION, "向移动端发送消息错误");
            }
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.debug("设备[{}]连接断开",ctx.channel().id());

        Channel channel = ctx.channel();
        deleteDevice(channel);  //卸载绑定的设备
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();    //关闭连接
        log.warn(cause.getMessage());
    }

    /**
     * 发送消息给指定设备
     * @param connectEnum 设备标识符
     * @param message 发送的消息
     */
    public static void sendMessage(ConnectEnum connectEnum, String message){
        try {
            switch (connectEnum){
                case CONNECT_ONE:
                    log.debug("向设备[{}]发送消息：{}",CONNECT_ONE.id(),message);
                    CONNECT_ONE.writeAndFlush(message);
                    break;
                case CONNECT_TWO:
                    log.debug("向设备[{}]发送消息：{}",CONNECT_TWO.id(),message);
                    CONNECT_TWO.writeAndFlush(message);
                    break;
                default:
            }
        }catch (NullPointerException exception){
            throw new ExceptionVo(ExceptionEnum.BUSINESS_EXCEPTION,"所选设备未连接");
        }

    }

    /**
     * 绑定设备
     * @param connectEnum 设备标识符
     * @param channel 设备通道
     */
    private void bindDevice(ConnectEnum connectEnum, Channel channel){
        switch (connectEnum){
            case CONNECT_ONE:
                log.debug("装载0号设备[{}]",channel.id());
                CONNECT_ONE = channel;
                break;
            case CONNECT_TWO:
                log.debug("装载1号设备[{}]",channel.id());
                CONNECT_TWO = channel;
            default:
        }
    }

    /**
     * 卸载设备
     * @param channel 设备通道
     */
    private void deleteDevice(Channel channel){
        if (Objects.equals(channel, CONNECT_ONE)){
            CONNECT_ONE = null;
            log.debug("卸载0号设备[{}]",channel.id());
        }else if (Objects.equals(channel, CONNECT_TWO)){
            CONNECT_TWO = null;
            log.debug("卸载1号设备[{}]",channel.id());
        }
    }

}
